/*
 * main.c
 *
 *  Created on: 19-01-2013
 *      Author: ja
 */

#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"

//lwip
#include "netif/ethernetif.h"
#include "lwip/tcpip.h"
#include "lwip/dhcp.h"

#include "rtos_tasks.h"
#include <stdio.h>

void lwIP_Init(void);
void vDHCP_TimerCallback(xTimerHandle pxTimer);
void ethernetInputTask(void* pvParameters);

volatile int tim_cnt = 0;

unsigned char dhcp_done;
// mutex used to guard access to USART resource
xSemaphoreHandle sem;
xTimerHandle xDHCP_Timer;

xTaskHandle xEthIntpuTskHandle;
xTaskHandle xLEDTskHandle;
xTaskHandle xStatTskHandle;

struct netif xNetIf;

// -----------------------------------------------------------------------------
//  main
// -----------------------------------------------------------------------------
int main (void)
{
//	sys_arch.h
//	cc.h
//	ethernetif.h
//dhcp_discover()	pbuf_allocStack overflow pbuf_alloc
//	conifgTCPIP_TASK_STACK_SIZE

//	LWIP_PLATFORM_DIAG("DIAG TEST\r\n");

	LWIP_DEBUGF(TCPIP_DEBUG, ("DEBUG test \n"));

	printf("Initialize LWIP...\r\n");
	lwIP_Init();

    sem = xSemaphoreCreateMutex();

    printf("Create DHCP timer...\r\n");
	xDHCP_Timer = xTimerCreate((signed char *) "DHCP_TIM", 500/portTICK_RATE_MS, pdTRUE, ( void * )12, vDHCP_TimerCallback);
//	if( xTimerStart(xDHCP_Timer, 0 ) != pdPASS ){
//		// The timer could not be set into the Active state.
//		printf("Timer cerate memory problem\r\n");
//	}

	printf("Create eth_input task...\r\n");
    // Create RTOS tasks
    if (pdPASS != xTaskCreate(ethernetInputTask, ( signed portCHAR* ) "eth_input", 1024, NULL, 5, &xEthIntpuTskHandle)) {
        // should never get here, unless there is a memory allocation problem
    	printf("Task cerate memory problem\r\n");
    }

    printf("Create led task...\r\n");
    // Create RTOS tasks
    if (pdPASS != xTaskCreate(TASK_LED1, ( signed portCHAR* ) "led1", 400, NULL, 3, &xLEDTskHandle )) {
        // should never get here, unless there is a memory allocation problem
    	printf("Task cerate memory problem\r\n");
    }

    printf("Create stat task...\r\n");
	if (pdPASS != xTaskCreate(TASK_STATISTICS, ( signed portCHAR * ) "stats", 800, NULL, 3, &xStatTskHandle )) {
	    // should never get here, unless there is a memory allocation problem
		printf("Task cerate memory problem\r\n");
	}

//    printf("Create uart task...\r\n");
//    if (pdPASS != xTaskCreate(TASK_USART, ( signed portCHAR* ) "usart1", configMINIMAL_STACK_SIZE, NULL, 3, NULL )) {
//        // should never get here, unless there is a memory allocation problem
//    }

//    if (pdPASS != xTaskCreate(TASK_USART, ( signed portCHAR* ) "usart2", configMINIMAL_STACK_SIZE, NULL, 3, NULL )) {
        // should never get here, unless there is a memory allocation problem
//    }

    printf("Start Scheduler\r\n");
    // start FreeRTOS scheduler - the RTOS takes control over the microcontroller
    vTaskStartScheduler();

    // program should never get here, unless there is a memory allocation problem
    while (1) {
        ;
    }

} /* main */

void lwIP_Init(void)
{
	ip_addr_t xIPAddr, xNetMask, xGateway;

//	lpc17xx_netif = mem_malloc(sizeof(struct netif));
	struct netif * netIf;
	tcpip_init(NULL, NULL);
	printf("tcpip init ok\r\n");
//	ip_addr_set_zero( &xGateway );
//	ip_addr_set_zero( &xIPAddr );
//	ip_addr_set_zero( &xNetMask );

	IP4_ADDR(&xGateway, 192,168,1,1);
	IP4_ADDR(&xIPAddr, 192,168,1,50);
	IP4_ADDR(&xNetMask, 255,255,255,0);

	netIf = netif_add(&xNetIf, &xIPAddr, &xNetMask, &xGateway, NULL, ethernetif_init, tcpip_input);
	if(netIf != NULL)
	{
		printf("netif added ok\r\n");
		netif_set_default(&xNetIf);
		printf("netif set default ok\r\n");
		netif_set_up(&xNetIf);
		printf("netif set up ok\r\n");
	}
	else
	{
		printf("lwIP_Init: Adding netif fail - netif == NULL\r\n");
	}

//	printf("Starting DHCP ...\r\n");
//	dhcp_start(&xNetIf);
	dhcp_done = 0;

}

void vDHCP_TimerCallback(xTimerHandle pxTimer)
{
	static unsigned int dhcpcnt = 0;
	dhcpcnt++;
	dhcp_fine_tmr();

	printf("tick	%d\r\n", dhcpcnt);

	if(dhcpcnt>=DHCP_COARSE_TIMER_SECS*2){
		dhcp_coarse_tmr();
		dhcpcnt=0;
		printf("big tick\r\n");
	}
	if(xNetIf.ip_addr.addr != 0)
	{
		dhcp_done = 1;
		printf("DHCP done\r\n");
		printf("My IP is: %d.%d.%d.%d\r\n", xNetIf.ip_addr.addr&0xff, (xNetIf.ip_addr.addr>>8)&0xff, (xNetIf.ip_addr.addr>>16)&0xff, (xNetIf.ip_addr.addr>>24)&0xff);
	}
}

void ethernetInputTask(void* pvParameters)
{
	while(1)
	{
		taskENTER_CRITICAL();
		ethernetif_input(&xNetIf);
		taskEXIT_CRITICAL();
		vTaskDelay(20/portTICK_RATE_MS);
	}
}

void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName ){
	printf("Task: %s", pcTaskName);
	printf("FreeRTOS Stack overflow\r\n");
	while(1);
}

void vApplicationMallocFailedHook(void){
	printf("Application malloc failed\r\n");
	while(1);
}

void HardFault_Handler(void)
{
	printf("hard fault\r\n");
	while(1);
}


void tim_config(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	/* Enable the TIM2 gloabal Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

	NVIC_Init(&NVIC_InitStructure);

	/* PCLK1 = HCLK/4 */
	RCC_PCLK1Config(RCC_HCLK_Div4);

	/* TIM2 clock enable */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 65535;
	TIM_TimeBaseStructure.TIM_Prescaler = 1000;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV4;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	/* TIM IT enable */
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

	TIM_Cmd(TIM2, ENABLE);
}


int get_tim(void)
{
	return (tim_cnt << 16) + TIM_GetCounter(TIM2);
}
